#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include <psp2/touch.h>

#include "touch_pad.h"
#include "ui.h"

#define SCROLL_TOUCH_DEAD_PIXLS 4
#define LONG_HOLD_INITIATE_COUNT 20
#define MAX_HOLD_COUNT 65535

#define lerp(value, from_max, to_max) ((((value * 10) * (to_max * 10)) / (from_max * 10)) / 10)

void resetTouch(TouchPad *pad)
{
    memset(pad, 0, sizeof(TouchPad));
}

void readTouch(TouchPad *pad)
{
    static int last_y_scroll_total_pixls = 0;

    int i;

    TouchReaport *reaport;
    TouchStates *states;
    TouchData *old, *current;

    pad->old_reaport_num = pad->reaport_num;

    for (i = 0; i < N_TOUCH_REPORTS; i++)
    {
        reaport = &pad->reaports[i];
        states = &reaport->states;
        old = &reaport->old;
        current = &reaport->current;

        states->old_touched = states->current_touched;
        states->old_x_scrolled = states->current_x_scrolled;
        states->old_y_scrolled = states->current_y_scrolled;

        states->current_touched = 0;
        states->current_x_scrolled = 0;
        states->current_y_scrolled = 0;

        memcpy(old, current, sizeof(TouchData));
        memset(current, 0, sizeof(TouchData));
    }

    SceTouchData touch_data;
    memset(&touch_data, 0, sizeof(SceTouchData));
    sceTouchPeek(0, &touch_data, 1);

    if (touch_data.reportNum < N_TOUCH_REPORTS)
        pad->reaport_num = touch_data.reportNum;
    else
        pad->reaport_num = N_TOUCH_REPORTS;

    for (i = 0; i < pad->reaport_num; i++)
    {
        reaport = &pad->reaports[i];
        states = &reaport->states;
        current = &reaport->current;

        states->current_touched = 1;
        current->x = lerp(touch_data.report[i].x, 1919, SCREEN_WIDTH);
        current->y = lerp(touch_data.report[i].y, 1087, SCREEN_HEIGHT);
    }

    for (i = 0; i < N_TOUCH_REPORTS; i++)
    {
        reaport = &pad->reaports[i];
        states = &reaport->states;
        old = &reaport->old;
        current = &reaport->current;

        if (states->current_touched && states->old_touched) // 获取滚动数据
        {
            int x_scroll_pixls = current->x - old->x;

            if (x_scroll_pixls < -SCROLL_TOUCH_DEAD_PIXLS || x_scroll_pixls > SCROLL_TOUCH_DEAD_PIXLS)
            {
                states->current_x_scrolled = 1;
                current->x_scroll_cur_pixls = x_scroll_pixls;

                if ((x_scroll_pixls > 0 && old->x_scroll_cur_pixls > 0) || (x_scroll_pixls < 0 && old->x_scroll_cur_pixls < 0))
                {
                    memcpy(&current->x_scroll_pixlsbuf, &old->x_scroll_pixlsbuf, sizeof(ScrollPixlsBuf));

                    current->x_scroll_total_pixls = old->x_scroll_total_pixls;
                    current->x_scroll_count = old->x_scroll_count;
                    if (current->x_scroll_count > N_PIXLS_BUFS)
                        current->x_scroll_total_pixls -= old->x_scroll_pixlsbuf.bufs[old->x_scroll_pixlsbuf.idx];
                }

                current->x_scroll_total_pixls += x_scroll_pixls;
                if (current->x_scroll_count < MAX_HOLD_COUNT)
                    current->x_scroll_count++;

                current->x_scroll_pixlsbuf.bufs[current->x_scroll_pixlsbuf.idx] = x_scroll_pixls;
                current->x_scroll_pixlsbuf.idx = (current->x_scroll_pixlsbuf.idx + 1) % N_PIXLS_BUFS;
            }

            int y_scroll_pixls = current->y - old->y;

            if (y_scroll_pixls < -SCROLL_TOUCH_DEAD_PIXLS || y_scroll_pixls > SCROLL_TOUCH_DEAD_PIXLS)
            {
                states->current_y_scrolled = 1;
                current->y_scroll_cur_pixls = y_scroll_pixls;

                if ((y_scroll_pixls > 0 && old->y_scroll_cur_pixls > 0) || (y_scroll_pixls < 0 && old->y_scroll_cur_pixls < 0))
                {
                    memcpy(&current->y_scroll_pixlsbuf, &old->y_scroll_pixlsbuf, sizeof(ScrollPixlsBuf));

                    current->y_scroll_total_pixls = old->y_scroll_total_pixls;
                    current->y_scroll_count = old->y_scroll_count;
                    if (current->y_scroll_count > N_PIXLS_BUFS)
                        current->y_scroll_total_pixls -= old->y_scroll_pixlsbuf.bufs[old->y_scroll_pixlsbuf.idx];
                }
                else
                {
                    last_y_scroll_total_pixls = 0;
                }

                last_y_scroll_total_pixls += y_scroll_pixls;
                current->y_scroll_total_pixls += y_scroll_pixls;
                if (current->y_scroll_count < MAX_HOLD_COUNT)
                    current->y_scroll_count++;

                current->y_scroll_pixlsbuf.bufs[current->y_scroll_pixlsbuf.idx] = y_scroll_pixls;
                current->y_scroll_pixlsbuf.idx = (current->y_scroll_pixlsbuf.idx + 1) % N_PIXLS_BUFS;
            }
        }

        states->pressed_touched = states->current_touched & ~states->old_touched;
        states->released_touched = ~states->current_touched & states->old_touched;

        states->pressed_x_scrolled = states->current_x_scrolled & ~states->old_x_scrolled;
        states->released_x_scrolled = ~states->current_x_scrolled & states->old_x_scrolled;

        states->pressed_y_scrolled = states->current_y_scrolled & ~states->old_y_scrolled;
        states->released_y_scrolled = ~states->current_y_scrolled & states->old_y_scrolled;

        if (states->current_touched)
        {
            if (states->old_touched)
            {
                current->hold_count = old->hold_count;
                current->beginning_long_motionless_hold = old->beginning_long_motionless_hold;
            }
            if (current->hold_count < MAX_HOLD_COUNT)
                current->hold_count++;

            if (!states->current_x_scrolled && !states->current_y_scrolled)
            {
                if (!states->old_x_scrolled && !states->old_y_scrolled)
                    current->motionless_hold_count = old->motionless_hold_count;

                if (current->motionless_hold_count < MAX_HOLD_COUNT)
                    current->motionless_hold_count++;
            }
        }

        if (current->hold_count >= LONG_HOLD_INITIATE_COUNT)
            current->long_hold = 1;

        if (current->motionless_hold_count >= LONG_HOLD_INITIATE_COUNT)
        {
            current->long_motionless_hold = 1;
            if (current->motionless_hold_count > current->hold_count - 3)
                current->beginning_long_motionless_hold = 1;
        }
    }

    if (pad->back_event_clicked)
    {
        pad->back_event_mode = 0;
        pad->back_event_clicked = 0;
    }

    // 底部往上滑触发返回事件
    if (pad->reaport_num == 1)
    {
        reaport = &pad->reaports[0];
        states = &reaport->states;
        old = &reaport->old;
        current = &reaport->current;

        if (states->pressed_y_scrolled)
        {
            if ((old->y > SCREEN_HEIGHT - 10) && (current->y_scroll_total_pixls < -SCROLL_TOUCH_DEAD_PIXLS))
                pad->back_event_mode = 1;
        }
    }

    if (pad->back_event_mode && pad->old_reaport_num == 1)
    {
        reaport = &pad->reaports[0];
        states = &reaport->states;
        old = &reaport->old;
        current = &reaport->current;

        if (states->released_touched && (last_y_scroll_total_pixls < -30) && old->hold_count < 40)
            pad->back_event_clicked = 1;
    }

    if (pad->reaport_num == 0 && pad->old_reaport_num <= 0)
    {
        pad->back_event_mode = 0;
        pad->back_event_clicked = 0;
        last_y_scroll_total_pixls = 0;
    }
}
